package com.alpha.processor.processor.anno_processor.base;

import com.alpha.processor.processor.tools.AnnoProcessorToolException;
import com.alpha.processor.processor.tools.ProcessorTool;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;

public abstract class AnnoProcessor {
    protected Messager messager;
    protected Elements elementUtils;
    protected ProcessorTool logger;

    public AnnoProcessor(Messager messager, Elements elementUtils, ProcessorTool logger) {
        this.messager = messager;
        this.elementUtils = elementUtils;
        this.logger = logger;
    }

    public abstract void processAnno(RoundEnvironment roundEnvironment);

    protected final TypeElement findTargetParentElement(@Nonnull TypeElement childElement,@Nonnull String targetName){
        List<TypeElement> parentElementList = new ArrayList<>();
        findAllParentType(parentElementList,childElement);
        for (TypeElement parentElement: parentElementList){
            if (targetName.equals(parentElement.getQualifiedName().toString())){
                return parentElement;
            }
        }
        return null;
    }

    private void findAllParentType(List<TypeElement> typeList, TypeElement childElement){
        List<? extends TypeMirror> parentTypeList = childElement.getInterfaces();
        for (TypeMirror typeMirror:parentTypeList){
            TypeElement element = getElementFromType(typeMirror);
            if (element != null){
                typeList.add(element);
                findAllParentType(typeList,element);
            }
        }
    }

    protected final TypeElement getElementFromType(@Nullable TypeMirror typeMirror){
        if (typeMirror == null){
            return null;
        }
        if (typeMirror.toString() == "none"){
            return null;
        }
        DeclaredType targetClassType = (DeclaredType) typeMirror;
        return (TypeElement) targetClassType.asElement();
    }
}
